#ifndef COMMON_JSONEX_H
#define COMMON_JSONEX_H

#include <nlohmann/json.hpp>
#include "Base.h"

using Json = nlohmann::json;

template<typename T>
T get(const Json& j, const std::string& key, T defaultValue)
{
    auto i = j.find(key);
    if (j.end() == i)
        return defaultValue;
    else
        return i->get<T>();
}


//============================================================================//
//                                                                            //
// 自定义数据序列化                                                             //
//                                                                            //
//============================================================================//

template <glm::length_t L>
struct nlohmann::adl_serializer<glm::vec<L, scalar>>
{
    static void to_json(Json& j, const glm::vec<L, scalar>& v)
    {
        for (glm::length_t i = 0; i < L; ++i)
            j[i] = v[i];
    }
    static void from_json(const Json& j, glm::vec<L, scalar>& v)
    {
        for (glm::length_t i = 0; i < L; ++i)
            v[i] = j[i];
    }
};

template <glm::length_t L>
struct nlohmann::adl_serializer<glm::mat<L, L, scalar>>
{
    static void to_json(Json& j, const glm::mat<L, L, scalar>& v)
    {
        for (glm::length_t c = 0; c < L; ++c)
            for (glm::length_t r = 0; r < L; ++r)
                j[c * L + r] = v[c][r];
    }
    static void from_json(const Json& j, glm::mat<L, L, scalar>& v)
    {
        for (glm::length_t c = 0; c < L; ++c)
            for (glm::length_t r = 0; r < L; ++r)
                v[c][r] = j[c * L + r];
    }
};

//============================================================================//
//                                                                            //
// 添加LOOSE的json读取。可以忽略json文件中多余的数据                          //
//                                                                            //
//============================================================================//

#define NLOHMANN_JSON_FROM_LOOSE(v1)                        \
    if (nlohmann_json_j.contains(#v1))                      \
    {                                                       \
        nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); \
    }

#ifdef NLOHMANN_DEFINE_TYPE_INTRUSIVE
#    undef NLOHMANN_DEFINE_TYPE_INTRUSIVE
#endif
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)                                   \
    friend void to_json(Json& nlohmann_json_j, const Type& nlohmann_json_t)         \
    {                                                                               \
        NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__))    \
    }                                                                               \
    friend void from_json(const Json& nlohmann_json_j, Type& nlohmann_json_t)       \
    {                                                                               \
        NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__))  \
    }                                                                               \
    friend void from_json_loose(const Json& nlohmann_json_j, Type& nlohmann_json_t) \
    {                                                                               \
        NLOHMANN_JSON_EXPAND(                                                       \
            NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_LOOSE, __VA_ARGS__))             \
    }

#ifdef NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
#    undef NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
#endif
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)                               \
    inline void to_json(Json& nlohmann_json_j, const Type& nlohmann_json_t)         \
    {                                                                               \
        NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__))    \
    }                                                                               \
    inline void from_json(const Json& nlohmann_json_j, Type& nlohmann_json_t)       \
    {                                                                               \
        NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__))  \
    }                                                                               \
    inline void from_json_loose(const Json& nlohmann_json_j, Type& nlohmann_json_t) \
    {                                                                               \
        NLOHMANN_JSON_EXPAND(                                                       \
            NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_LOOSE, __VA_ARGS__))             \
    }

#endif // COMMON_JSONEX_H